From 2b0e8f2d85418a5a2f50e3e04732dec906f2bf73 Mon Sep 17 00:00:00 2001 From: Nicolas BESNARD Date: Mon, 20 Jan 2025 16:05:29 +0000 Subject: [PATCH] ubus: implement retransmission configuration via ubus MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Problem: odhcp6c uses static retransmission parameters defined in RFC3315. Solution: Make retransmission parameters configurable via ubus and update the default values based on RFC8815. Signed-off-by: Nicolas BESNARD Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcp6c/pull/106 Signed-off-by: Álvaro Fernández Rojas --- src/config.c | 136 ++++++++++++++++++++++++++++--- src/config.h | 33 +++++++- src/dhcpv6.c | 218 +++++++++++++++++++++++++++++++++++++++++--------- src/odhcp6c.c | 18 ++--- src/odhcp6c.h | 41 ++++++---- src/ubus.c | 148 +++++++++++++++++++++++++++++++++- 6 files changed, 511 insertions(+), 83 deletions(-) diff --git a/src/config.c b/src/config.c index 1b18730..b0ba835 100644 --- a/src/config.c +++ b/src/config.c @@ -80,7 +80,6 @@ struct config_dhcp *config_dhcp_get(void) { void config_dhcp_reset(void) { config_dhcp.release = true; config_dhcp.dscp = 0; - config_dhcp.sol_timeout = DHCPV6_SOL_MAX_RT; config_dhcp.sk_prio = 0; config_dhcp.stateful_only_mode = false; config_dhcp.ia_na_mode = IA_MODE_TRY; @@ -88,6 +87,27 @@ void config_dhcp_reset(void) { config_dhcp.client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE; config_dhcp.allow_slaac_only = -1; config_dhcp.oro_user_cnt = 0; + memset(config_dhcp.message_rtx, 0, sizeof(config_dhcp.message_rtx)); + config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].delay_max = DHCPV6_MAX_DELAY; + config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_init = DHCPV6_SOL_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_max = DHCPV6_SOL_MAX_RT; + config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_init = DHCPV6_REQ_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_max = DHCPV6_REQ_MAX_RT; + config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].rc_max = DHCPV6_REQ_MAX_RC; + config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_init = DHCPV6_REN_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_max = DHCPV6_REN_MAX_RT; + config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_init = DHCPV6_REB_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_max = DHCPV6_REB_MAX_RT; + config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].delay_max = DHCPV6_MAX_DELAY; + config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_init = DHCPV6_INF_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_max = DHCPV6_INF_MAX_RT; + config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].timeout_init = DHCPV6_REL_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].rc_max = DHCPV6_REL_MAX_RC; + config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].timeout_init = DHCPV6_DEC_INIT_RT; + config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].rc_max = DHCPV6_DEC_MAX_RC; + config_dhcp.irt_default = DHCPV6_IRT_DEFAULT; + config_dhcp.irt_min = DHCPV6_IRT_MIN; + config_dhcp.rand_factor = DHCPV6_RAND_FACTOR; } void config_set_release(bool enable) { @@ -95,24 +115,19 @@ void config_set_release(bool enable) { } bool config_set_dscp(unsigned int value) { - if (value > 63) + if (value > 63) { + syslog(LOG_ERR, "Invalid DSCP value"); return false; + } config_dhcp.dscp = value; return true; } -bool config_set_solicit_timeout(unsigned int timeout) { - if (timeout > INT32_MAX) - return false; - - config_dhcp.sol_timeout = timeout; - return true; -} - bool config_set_sk_priority(unsigned int priority) { - if (priority > 6) + if (priority > 6) { + syslog(LOG_ERR, "Invalid SK priority value"); return false; - + } config_dhcp.sk_prio = priority; return true; } @@ -134,6 +149,7 @@ bool config_set_request_addresses(char* mode) { } else if (!strcmp(mode, "try")) { config_dhcp.ia_na_mode = IA_MODE_TRY; } else { + syslog(LOG_ERR, "Invalid IA_NA Request Addresses mode"); return false; } @@ -186,11 +202,14 @@ void config_clear_requested_options(void) { } bool config_add_requested_options(unsigned int option) { - if (option > UINT16_MAX) + if (option > UINT16_MAX) { + syslog(LOG_ERR, "Invalid requested option"); return false; + } option = htons(option); if (odhcp6c_insert_state(STATE_ORO, 0, &option, 2)) { + syslog(LOG_ERR, "Failed to set requested option"); return false; } config_dhcp.oro_user_cnt++; @@ -205,6 +224,76 @@ bool config_add_send_options(char* option) { return (config_parse_opt(option) == 0); } +bool config_set_rtx_delay_max(enum config_dhcp_msg msg, unsigned int value) +{ + if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX) { + syslog(LOG_ERR, "Invalid retransmission Maximum Delay value"); + return false; + } + config_dhcp.message_rtx[msg].delay_max = value; + return true; +} + +bool config_set_rtx_timeout_init(enum config_dhcp_msg msg, unsigned int value) +{ + if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX || value == 0) { + syslog(LOG_ERR, "Invalid retransmission Initial Timeout value"); + return false; + } + config_dhcp.message_rtx[msg].timeout_init = value; + return true; +} + +bool config_set_rtx_timeout_max(enum config_dhcp_msg msg, unsigned int value) +{ + if (msg >= CONFIG_DHCP_MAX || value > UINT16_MAX) { + syslog(LOG_ERR, "Invalid retransmission Maximum Timeout value"); + return false; + } + config_dhcp.message_rtx[msg].timeout_max = value; + return true; +} + +bool config_set_rtx_rc_max(enum config_dhcp_msg msg, unsigned int value) +{ + if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX) { + syslog(LOG_ERR, "Invalid retransmission Retry Attempt value"); + return false; + } + config_dhcp.message_rtx[msg].rc_max = value; + return true; +} + +bool config_set_irt_default(unsigned int value) +{ + if (value == 0) { + syslog(LOG_ERR, "Invalid Default Information Refresh Time value"); + return false; + } + config_dhcp.irt_default = value; + return true; +} + +bool config_set_irt_min(unsigned int value) +{ + if (value == 0) { + syslog(LOG_ERR, "Invalid Minimum Information Refresh Time value"); + return false; + } + config_dhcp.irt_min = value; + return true; +} + +bool config_set_rand_factor(unsigned int value) +{ + if (value > 999 || value < 10) { + syslog(LOG_ERR, "Invalid Random Factor value"); + return false; + } + config_dhcp.rand_factor = value; + return true; +} + static int config_parse_opt_u8(const char *src, uint8_t **dst) { int len = strlen(src); @@ -481,3 +570,24 @@ int config_parse_opt(const char *opt) return ret; } + +void config_apply_dhcp_rtx(struct dhcpv6_retx* dhcpv6_retx) +{ + dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_delay = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].delay_max; + dhcpv6_retx[DHCPV6_MSG_SOLICIT].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_init; + dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_max; + dhcpv6_retx[DHCPV6_MSG_REQUEST].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_init; + dhcpv6_retx[DHCPV6_MSG_REQUEST].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_max; + dhcpv6_retx[DHCPV6_MSG_REQUEST].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].rc_max; + dhcpv6_retx[DHCPV6_MSG_RENEW].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_init; + dhcpv6_retx[DHCPV6_MSG_RENEW].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_max; + dhcpv6_retx[DHCPV6_MSG_REBIND].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_init; + dhcpv6_retx[DHCPV6_MSG_REBIND].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_max; + dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_delay = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].delay_max; + dhcpv6_retx[DHCPV6_MSG_INFO_REQ].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_init; + dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_max; + dhcpv6_retx[DHCPV6_MSG_RELEASE].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].timeout_init; + dhcpv6_retx[DHCPV6_MSG_RELEASE].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].rc_max; + dhcpv6_retx[DHCPV6_MSG_DECLINE].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].timeout_init; + dhcpv6_retx[DHCPV6_MSG_DECLINE].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].rc_max; +} \ No newline at end of file diff --git a/src/config.h b/src/config.h index a664e45..f0edade 100644 --- a/src/config.h +++ b/src/config.h @@ -65,10 +65,27 @@ #include "odhcp6c.h" +struct config_dhcp_rtx { + uint8_t delay_max; + uint8_t timeout_init; + uint16_t timeout_max; + uint8_t rc_max; +}; + +enum config_dhcp_msg { + CONFIG_DHCP_SOLICIT, + CONFIG_DHCP_REQUEST, + CONFIG_DHCP_RENEW, + CONFIG_DHCP_REBIND, + CONFIG_DHCP_RELEASE, + CONFIG_DHCP_DECLINE, + CONFIG_DHCP_INFO_REQ, + CONFIG_DHCP_MAX +}; + struct config_dhcp { bool release; int dscp; - int sol_timeout; int sk_prio; bool stateful_only_mode; enum odhcp6c_ia_mode ia_na_mode; @@ -76,13 +93,16 @@ struct config_dhcp { unsigned int client_options; int allow_slaac_only; unsigned int oro_user_cnt; + struct config_dhcp_rtx message_rtx[CONFIG_DHCP_MAX]; + uint32_t irt_default; + uint32_t irt_min; + uint16_t rand_factor; }; struct config_dhcp *config_dhcp_get(void); void config_dhcp_reset(void); void config_set_release(bool enable); bool config_set_dscp(unsigned int value) ; -bool config_set_solicit_timeout(unsigned int timeout); bool config_set_sk_priority(unsigned int priority); void config_set_client_options(enum dhcpv6_config option, bool enable); bool config_set_request_addresses(char *mode); @@ -94,9 +114,18 @@ void config_clear_requested_options(void) ; bool config_add_requested_options(unsigned int option); void config_clear_send_options(void); bool config_add_send_options(char *option); +bool config_set_rtx_delay_max(enum config_dhcp_msg msg, unsigned int value); +bool config_set_rtx_timeout_init(enum config_dhcp_msg msg, unsigned int value); +bool config_set_rtx_timeout_max(enum config_dhcp_msg msg, unsigned int value); +bool config_set_rtx_rc_max(enum config_dhcp_msg msg, unsigned int value); +bool config_set_irt_default(unsigned int value); +bool config_set_irt_min(unsigned int value); +bool config_set_rand_factor(unsigned int value); int config_add_opt(const uint16_t code, const uint8_t *data, const uint16_t len); int config_parse_opt_data(const char *data, uint8_t **dst, const unsigned int type, const bool array); int config_parse_opt(const char *opt); +void config_apply_dhcp_rtx(struct dhcpv6_retx* dhcpv6_retx); + #endif /* _CONFIG_H_ */ diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 50ec027..f2f3cd9 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -36,6 +36,7 @@ #include #include +#include "config.h" #include "odhcp6c.h" @@ -44,7 +45,6 @@ #define DHCPV6_CLIENT_PORT 546 #define DHCPV6_SERVER_PORT 547 #define DHCPV6_DUID_LLADDR 3 -#define DHCPV6_REQ_DELAY 1 #define DHCPV6_SOL_MAX_RT_MIN 60 #define DHCPV6_SOL_MAX_RT_MAX 86400 @@ -80,20 +80,158 @@ static int dhcpv6_commit_advert(void); // RFC 3315 - 5.5 Timeout and Delay values static const struct dhcpv6_retx dhcpv6_retx_default[_DHCPV6_MSG_MAX] = { - [DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "", - dhcpv6_handle_reconfigure, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT", - dhcpv6_handle_advert, dhcpv6_commit_advert, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST", - dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW", - dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND", - dhcpv6_handle_rebind_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL, false, 0, 0, 0,{0, 0, 0}, 0, 0, 0, -1, 0}, - [DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ", - dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0}, + [DHCPV6_MSG_UNKNOWN] = { + 0, + 1, + 120, + 0, + "", + dhcpv6_handle_reconfigure, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_SOLICIT] = { + DHCPV6_MAX_DELAY, + DHCPV6_SOL_INIT_RT, + DHCPV6_SOL_MAX_RT, + 0, + "SOLICIT", + dhcpv6_handle_advert, + dhcpv6_commit_advert, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_REQUEST] = { + 0, + DHCPV6_REQ_INIT_RT, + DHCPV6_REQ_MAX_RT, + DHCPV6_REQ_MAX_RC, + "REQUEST", + dhcpv6_handle_reply, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_RENEW] = { + 0, + DHCPV6_REN_INIT_RT, + DHCPV6_REN_MAX_RT, + 0, + "RENEW", + dhcpv6_handle_reply, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_REBIND] = { + 0, + DHCPV6_REB_INIT_RT, + DHCPV6_REB_MAX_RT, + 0, + "REBIND", + dhcpv6_handle_rebind_reply, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_RELEASE] = { + 0, + DHCPV6_REL_INIT_RT, + 0, + DHCPV6_REL_MAX_RC, + "RELEASE", + NULL, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_DECLINE] = { + 0, + DHCPV6_DEC_INIT_RT, + 0, + DHCPV6_DEC_MAX_RC, + "DECLINE", + NULL, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, + [DHCPV6_MSG_INFO_REQ] = { + DHCPV6_MAX_DELAY, + DHCPV6_INF_INIT_RT, + DHCPV6_INF_MAX_RT, + 0, + "INFOREQ", + dhcpv6_handle_reply, + NULL, + false, + 0, + 0, + 0, + {0, 0, 0}, + 0, + 0, + 0, + -1, + 0 + }, }; static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {0}; @@ -122,6 +260,9 @@ static unsigned int client_options = 0; // counters for statistics static struct dhcpv6_stats dhcpv6_stats = {0}; +// config +static struct config_dhcp* config_dhcp = NULL; + static uint32_t ntohl_unaligned(const uint8_t *data) { uint32_t buf; @@ -402,11 +543,14 @@ void dhcpv6_reset_stats(void) memset(&dhcpv6_stats, 0, sizeof(dhcpv6_stats)); } -int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout, unsigned int dscp) +int init_dhcpv6(const char *ifname) { + config_dhcp = config_dhcp_get(); + memcpy(dhcpv6_retx, dhcpv6_retx_default, sizeof(dhcpv6_retx)); - client_options = options; - dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_timeout; + config_apply_dhcp_rtx(dhcpv6_retx); + + client_options = config_dhcp->client_options; sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); if (sock < 0) @@ -498,10 +642,10 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_t if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) goto failure; - if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &sk_prio, sizeof(sk_prio)) < 0) + if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &(config_dhcp->sk_prio), sizeof(config_dhcp->sk_prio)) < 0) goto failure; - val = dscp << 2; + val = config_dhcp->dscp << 2; if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) { goto failure; } @@ -868,7 +1012,7 @@ static int64_t dhcpv6_rand_delay(int64_t time) int random; odhcp6c_random(&random, sizeof(random)); - return (time * ((int64_t)random % 1000LL)) / 10000LL; + return (time * ((int64_t)random % (config_dhcp->rand_factor*10LL))) / 10000LL; } // Message validation checks according to RFC3315 chapter 15 @@ -1134,7 +1278,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, { uint8_t *odata; uint16_t otype, olen; - uint32_t refresh = 86400; + uint32_t refresh = config_dhcp->irt_default; int ret = 1; unsigned int state_IAs; unsigned int updated_IAs = 0; @@ -1401,7 +1545,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_clear_state(STATE_SERVER_ADDR); odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16); - t1 = refresh; + t1 = (refresh < config_dhcp->irt_min) ? config_dhcp->irt_min : refresh; break; default: @@ -1838,23 +1982,23 @@ int dhcpv6_send_request(enum dhcpv6_msg type) struct dhcpv6_retx *retx = &dhcpv6_retx[type]; uint64_t current_milli_time = 0; - if (retx->delay ) { - if (retx->delay_msec == 0) { - retx->delay_msec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2); - dhcpv6_set_state_timeout(retx->delay_msec); - retx->delay_msec += odhcp6c_get_milli_time(); - return 1; - } else { - current_milli_time = odhcp6c_get_milli_time(); - if (current_milli_time < retx->delay_msec) { - dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time); + if (!retx->is_retransmit) { + if (retx->max_delay) { + if (retx->delay_msec == 0) { + retx->delay_msec = (dhcpv6_rand_delay((10000 * retx->max_delay) / 2) + (1000 * retx->max_delay) / 2); + dhcpv6_set_state_timeout(retx->delay_msec); + retx->delay_msec += odhcp6c_get_milli_time(); return 1; + } else { + current_milli_time = odhcp6c_get_milli_time(); + if (current_milli_time < retx->delay_msec) { + dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time); + return 1; + } + retx->delay_msec = 0; } - retx->delay_msec = 0; } - } - - if (!retx->is_retransmit) { + retx->is_retransmit = true; retx->rc = 0; retx->timeout = UINT32_MAX; diff --git a/src/odhcp6c.c b/src/odhcp6c.c index c36e3e3..78de3b7 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -363,13 +363,11 @@ int main(_unused int argc, char* const argv[]) break; case 't': - config_set_solicit_timeout(atoi(optarg)); + config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, atoi(optarg)); break; case 'C': - if (!config_set_dscp(atoi(optarg))) { - syslog(LOG_ERR, "Invalid DSCP value, using default (0)"); - } + config_set_dscp(atoi(optarg)); break; case 'm': @@ -517,7 +515,7 @@ int main(_unused int argc, char* const argv[]) odhcp6c_get_state(STATE_ORO, &oro_len); config_dhcp->oro_user_cnt = oro_len / sizeof(uint16_t); - if (init_dhcpv6(ifname, config_dhcp->client_options, config_dhcp->sk_prio, config_dhcp->sol_timeout, config_dhcp->dscp)) { + if (init_dhcpv6(ifname)) { syslog(LOG_ERR, "failed to initialize: %s", strerror(errno)); return 1; } @@ -666,9 +664,6 @@ int main(_unused int argc, char* const argv[]) case DHCPV6_SOLICIT_PROCESSING: case DHCPV6_REQUEST_PROCESSING: res = dhcpv6_state_processing(msg_type); - - if (signal_usr2 || signal_term) - dhcpv6_set_state(DHCPV6_EXIT); break; case DHCPV6_BOUND_PROCESSING: @@ -678,8 +673,6 @@ int main(_unused int argc, char* const argv[]) if (signal_usr1) dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW); - if (signal_usr2 || signal_term) - dhcpv6_set_state(DHCPV6_EXIT); break; case DHCPV6_RENEW_PROCESSING: @@ -688,8 +681,6 @@ int main(_unused int argc, char* const argv[]) if (signal_usr1) signal_usr1 = false; // Acknowledged - if (signal_usr2 || signal_term) - dhcpv6_set_state(DHCPV6_EXIT); break; case DHCPV6_EXIT: @@ -736,6 +727,9 @@ int main(_unused int argc, char* const argv[]) break; } + if (signal_usr2 || signal_term) + dhcpv6_set_state(DHCPV6_EXIT); + poll_res = poll(fds, nfds, dhcpv6_get_state_timeout()); dhcpv6_reset_state_timeout(); if (poll_res == -1 && (errno == EINTR || errno == EAGAIN)) { diff --git a/src/odhcp6c.h b/src/odhcp6c.h index c398269..ac2dd32 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -26,12 +26,32 @@ #define ND_OPT_RECURSIVE_DNS 25 #define ND_OPT_DNSSL 31 +#define DHCPV6_MAX_DELAY 1 +#define DHCPV6_IRT_DEFAULT 86400 +#define DHCPV6_IRT_MIN 600 +#define DHCPV6_RAND_FACTOR 100 + +#define DHCPV6_SOL_INIT_RT 1 #define DHCPV6_SOL_MAX_RT 120 + +#define DHCPV6_REQ_INIT_RT 1 #define DHCPV6_REQ_MAX_RT 30 -#define DHCPV6_CNF_MAX_RT 4 +#define DHCPV6_REQ_MAX_RC 10 + +#define DHCPV6_REN_INIT_RT 10 #define DHCPV6_REN_MAX_RT 600 + +#define DHCPV6_REB_INIT_RT 10 #define DHCPV6_REB_MAX_RT 600 -#define DHCPV6_INF_MAX_RT 120 + +#define DHCPV6_INF_INIT_RT 1 +#define DHCPV6_INF_MAX_RT 3600 + +#define DHCPV6_REL_INIT_RT 1 +#define DHCPV6_REL_MAX_RC 4 + +#define DHCPV6_DEC_INIT_RT 1 +#define DHCPV6_DEC_MAX_RC 4 #define RA_MIN_ADV_INTERVAL 3 /* RFC 4861 paragraph 6.2.1 */ @@ -202,7 +222,7 @@ typedef int(reply_handler)(enum dhcpv6_msg orig, const int rc, // retransmission strategy struct dhcpv6_retx { - bool delay; + uint8_t max_delay; uint8_t init_timeo; uint16_t max_timeo; uint8_t max_rc; @@ -445,7 +465,7 @@ struct odhcp6c_opt { const char *str; }; -int init_dhcpv6(const char *ifname, unsigned int client_options, int sk_prio, int sol_timeout, unsigned int dscp); +int init_dhcpv6(const char *ifname); int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd, bool stateful_only); int dhcpv6_promote_server_cand(void); int dhcpv6_send_request(enum dhcpv6_msg type); @@ -472,19 +492,6 @@ int ra_get_retransmit(void); void notify_state_change(const char *status, int delay, bool resume); -void config_set_release(bool enable); -bool config_set_dscp(unsigned int value); -bool config_set_solicit_timeout(unsigned int timeout); -bool config_set_sk_priority(unsigned int value); -void config_set_client_options(enum dhcpv6_config option, bool enable); -bool config_set_request_addresses(char *mode); -bool config_set_request_prefix(unsigned int length, unsigned int id); -void config_set_stateful_only(bool enable); -void config_clear_requested_options(void); -bool config_add_requested_options(unsigned int option); -void config_clear_send_options(void); -bool config_add_send_options(char *option); - int script_init(const char *path, const char *ifname); ssize_t script_unhexlify(uint8_t *dst, size_t len, const char *src); void script_hexlify(char *dst, const uint8_t *src, size_t len); diff --git a/src/ubus.c b/src/ubus.c index 71418a4..fde51bf 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -71,6 +71,7 @@ #include #include "ubus.h" +#include "config.h" #define CHECK(stmt) \ do { \ @@ -111,6 +112,16 @@ enum { RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES, RECONFIGURE_DHCP_ATTR_REQ_PREFIXES, RECONFIGURE_DHCP_ATTR_STATEFUL, + RECONFIGURE_DHCP_ATTR_MSG_SOLICIT, + RECONFIGURE_DHCP_ATTR_MSG_REQUEST, + RECONFIGURE_DHCP_ATTR_MSG_RENEW, + RECONFIGURE_DHCP_ATTR_MSG_REBIND, + RECONFIGURE_DHCP_ATTR_MSG_RELEASE, + RECONFIGURE_DHCP_ATTR_MSG_DECLINE, + RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ, + RECONFIGURE_DHCP_ATTR_IRT_DEFAULT, + RECONFIGURE_DHCP_ATTR_IRT_MIN, + RECONFIGURE_DHCP_ATTR_RAND_FACTOR, RECONFIGURE_DHCP_ATTR_MAX, }; @@ -141,6 +152,16 @@ static const struct blobmsg_policy reconfigure_dhcp_policy[RECONFIGURE_DHCP_ATTR [RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES] = { .name = "req_addresses", .type = BLOBMSG_TYPE_STRING}, [RECONFIGURE_DHCP_ATTR_REQ_PREFIXES] = { .name = "req_prefixes", .type = BLOBMSG_TYPE_INT32}, [RECONFIGURE_DHCP_ATTR_STATEFUL] = { .name = "stateful_only", .type = BLOBMSG_TYPE_BOOL}, + [RECONFIGURE_DHCP_ATTR_MSG_SOLICIT] = { .name = "msg_solicit", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_REQUEST] = { .name = "msg_request", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_RENEW] = { .name = "msg_renew", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_REBIND] = { .name = "msg_rebind", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_RELEASE] = { .name = "msg_release", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_DECLINE] = { .name = "msg_decline", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ] = { .name = "msg_inforeq", .type = BLOBMSG_TYPE_TABLE}, + [RECONFIGURE_DHCP_ATTR_IRT_DEFAULT] = { .name = "irt_default", .type = BLOBMSG_TYPE_INT32}, + [RECONFIGURE_DHCP_ATTR_IRT_MIN] = { .name = "irt_min", .type = BLOBMSG_TYPE_INT32}, + [RECONFIGURE_DHCP_ATTR_RAND_FACTOR] = { .name = "rand_factor", .type = BLOBMSG_TYPE_INT32}, }; static struct ubus_method odhcp6c_object_methods[] = { @@ -606,7 +627,6 @@ static int ubus_handle_reset_stats(_unused struct ubus_context *ctx, _unused str return UBUS_STATUS_OK; } - static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_object *obj, struct ubus_request_data *req, _unused const char *method, _unused struct blob_attr *msg) @@ -618,6 +638,44 @@ static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_o return UBUS_STATUS_OK; } +static int ubus_handle_reconfigure_dhcp_rtx(enum config_dhcp_msg msg, struct blob_attr* table) +{ + struct blob_attr *cur = NULL; + uint32_t value = 0; + size_t rem = 0; + + if (msg >= CONFIG_DHCP_MAX || blobmsg_data_len(table) == 0) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_for_each_attr(cur, table, rem) { + if (!blobmsg_check_attr(cur, true) || blobmsg_type(cur) != BLOBMSG_TYPE_INT32) + return UBUS_STATUS_INVALID_ARGUMENT; + + const char* name = blobmsg_name(cur); + if (strcmp("delay_max", name) == 0) { + value = blobmsg_get_u32(cur); + if (!config_set_rtx_delay_max(msg, value)) + return UBUS_STATUS_INVALID_ARGUMENT; + } else if (strcmp("timeout_init", name) == 0 ) { + value = blobmsg_get_u32(cur); + if (!config_set_rtx_timeout_init(msg, value)) + return UBUS_STATUS_INVALID_ARGUMENT; + } else if (strcmp("timeout_max", name) == 0 ) { + value = blobmsg_get_u32(cur); + if (!config_set_rtx_timeout_max(msg, value)) + return UBUS_STATUS_INVALID_ARGUMENT; + } else if (strcmp("rc_max", name) == 0) { + value = blobmsg_get_u32(cur); + if (!config_set_rtx_rc_max(msg, value)) + return UBUS_STATUS_INVALID_ARGUMENT; + } else { + return UBUS_STATUS_INVALID_ARGUMENT; + } + } + + return UBUS_STATUS_OK; +} + static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unused struct ubus_object *obj, _unused struct ubus_request_data *req, _unused const char *method, struct blob_attr *msg) @@ -652,7 +710,7 @@ static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unuse if ((cur = tb[RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT])) { value = blobmsg_get_u32(cur); - if (!config_set_solicit_timeout(value)) + if (!config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, value)) return UBUS_STATUS_INVALID_ARGUMENT; need_reinit = true; valid_args = true; @@ -755,6 +813,92 @@ static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unuse valid_args = true; } + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_SOLICIT])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_SOLICIT, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REQUEST])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REQUEST, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RENEW])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RENEW, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REBIND])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REBIND, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RELEASE])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RELEASE, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_DECLINE])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_DECLINE, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ])) { + if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_INFO_REQ, cur)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_MIN])) { + value = blobmsg_get_u32(cur); + + if (!config_set_irt_min(value)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_DEFAULT])) { + value = blobmsg_get_u32(cur); + + if (!config_set_irt_default(value)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + + if ((cur = tb[RECONFIGURE_DHCP_ATTR_RAND_FACTOR])) { + value = blobmsg_get_u32(cur); + + if (!config_set_rand_factor(value)) + return UBUS_STATUS_INVALID_ARGUMENT; + + need_reinit = true; + valid_args = true; + } + if (need_reinit) raise(SIGUSR2); -- 2.30.2